package hr.web.jsf.render;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIForm;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
import javax.servlet.http.HttpServletRequest;

public class DataScrollerRenderer extends Renderer {
	@Override
	public void encodeBegin(FacesContext context, UIComponent component)
			throws IOException {
		if (Boolean.parseBoolean((String) component.getAttributes().get(
				"bookmarkable")) == true) {
			decode(context, component);
		}

		String id = component.getClientId(context);
		UIComponent parent = component;
		while (!(parent instanceof UIForm))
			parent = parent.getParent();
		String formId = parent.getClientId(context);

		ResponseWriter writer = context.getResponseWriter();

		String styleClass = (String) component.getAttributes()
				.get("styleClass");
		String selectedStyleClass = (String) component.getAttributes().get(
				"selectedStyleClass");
		String dataTableId = (String) component.getAttributes().get(
				"dataTableId");
		Integer a = Integer.parseInt((String) component.getAttributes().get(
				"showpages"));
		int showpages = a == null ? 0 : a.intValue();

		// find the component with the given ID

		UIData data = (UIData) component.findComponent(dataTableId);

		int first = data.getFirst();
		int itemcount = data.getRowCount();
		int pagesize = data.getRows();
		if (pagesize <= 0)
			pagesize = itemcount;

		int pages = itemcount / pagesize;
		if (itemcount % pagesize != 0)
			pages++;

		int currentPage = first / pagesize;
		if (first >= itemcount - pagesize)
			currentPage = pages - 1;
		int startPage = 0;
		int endPage = pages;
		if (showpages > 0) {
			startPage = (currentPage / showpages) * showpages;
			endPage = Math.min(startPage + showpages, pages);
		}

		writer.startElement("div", component);
		writer.writeAttribute("class", "pages", null);

		if (currentPage > 0)
			writeLink(writer, component, formId, id, "" + (currentPage), "<",
					styleClass);

		if (startPage > 0)
			writeLink(writer, component, formId, id, "" + startPage, "<<",
					styleClass);

		for (int i = startPage; i < endPage; i++) {
			if(i == currentPage){
				writeBlindLink(writer, component, formId, id, "" + (i + 1), "" + (i + 1), selectedStyleClass);	
			}else{
				writeLink(writer, component, formId, id, "" + (i + 1), "" + (i + 1), styleClass);
			}
		}

		if (endPage + 1 < pages)
			writeLink(writer, component, formId, id, "" + (endPage + 1), ">>",
					styleClass);

		if (first < itemcount - pagesize)
			writeLink(writer, component, formId, id, "" + (currentPage + 2),
					">", styleClass);

		writer.endElement("div");

		// hidden field to hold result
		writeHiddenField(writer, component, id);
	}

	private void writeLink(ResponseWriter writer, UIComponent component,
			String formId, String id, String value, String text,
			String styleClass) throws IOException {
		if (Boolean.parseBoolean((String) component.getAttributes().get(
				"bookmarkable")) == true) {
			writeBookmarkableLink(writer, component, formId, id, value, text,
					styleClass);
		} else {
			writeSubmitLink(writer, component, formId, id, value, styleClass);
		}
	}

	private void writeSubmitLink(ResponseWriter writer, UIComponent component,
			String formId, String id, String value, String styleClass)
			throws IOException {
		writer.writeText(" ", null);
		writer.startElement("a", component);
		writer.writeAttribute("href", "#", null);
		writer.writeAttribute("onclick", onclickCode(formId, id, value), null);
		if (styleClass != null)
			writer.writeAttribute("class", styleClass, "styleClass");
		writer.writeText(value, null);
		writer.endElement("a");
	}

	private void writeBookmarkableLink(ResponseWriter writer,
			UIComponent component, String formId, String id, String value,
			String text, String styleClass) throws IOException {
		HttpServletRequest req = ((HttpServletRequest) FacesContext
				.getCurrentInstance().getExternalContext().getRequest());
		writer.writeText(" ", null);
		writer.startElement("a", component);
		String queryUrl = "";
		List<UIParameter> params = getParams(component);
		for (UIParameter parameter : params) {
			queryUrl += parameter.getName() + "=" + parameter.getValue() + "&";
		}
		if (queryUrl.endsWith("&"))
			queryUrl = queryUrl.substring(0, queryUrl.length() - 1);
		writer.writeAttribute("href", req.getRequestURL().append(
				"?page=" + value).append("&" + queryUrl).toString(), null);
		if (styleClass != null)
			writer.writeAttribute("class", styleClass, "styleClass");
		writer.writeText(text, null);
		writer.endElement("a");
	}
	private void writeBlindLink(ResponseWriter writer,
			UIComponent component, String formId, String id, String value,
			String text, String styleClass) throws IOException {
		HttpServletRequest req = ((HttpServletRequest) FacesContext
				.getCurrentInstance().getExternalContext().getRequest());
		writer.writeText(" ", null);
		writer.startElement("a", component);
		writer.writeAttribute("href", "#", null);
		if (styleClass != null)
			writer.writeAttribute("class", styleClass, "styleClass");
		writer.writeText(text, null);
		writer.endElement("a");
	}

	private String onclickCode(String formId, String id, String value) {
		StringBuilder builder = new StringBuilder();
		builder.append("document.forms[");
		builder.append("'");
		builder.append(formId);
		builder.append("'");
		builder.append("]['");
		builder.append(id);
		builder.append("'].value='");
		builder.append(value);
		builder.append("';");
		builder.append(" document.forms[");
		builder.append("'");
		builder.append(formId);
		builder.append("'");
		builder.append("].submit()");
		builder.append("; return false;");
		return builder.toString();
	}

	private void writeHiddenField(ResponseWriter writer, UIComponent component,
			String id) throws IOException {
		writer.startElement("input", component);
		writer.writeAttribute("type", "hidden", null);
		writer.writeAttribute("name", id, null);
		writer.endElement("input");
	}

	@Override
	public void decode(FacesContext context, UIComponent component) {
		String id = component.getClientId(context);
		Map<String, String> parameters = context.getExternalContext()
				.getRequestParameterMap();

		String response = null;
		if (Boolean.parseBoolean((String) component.getAttributes().get(
				"bookmarkable")) == true) {
			response = parameters.get("page");
			if (response == null || response.equals(""))
				response = "1";
		} else {
			response = parameters.get(id);
			if (response == null || response.equals(""))
				return;
		}

		String dataTableId = (String) component.getAttributes().get(
				"dataTableId");
		Integer a = Integer.parseInt((String) component.getAttributes().get(
				"showpages"));
		int showpages = a == null ? 0 : a.intValue();

		UIData data = (UIData) component.findComponent(dataTableId);

		int first = data.getFirst();
		int itemcount = data.getRowCount();
		int pagesize = data.getRows();
		if (pagesize <= 0)
			pagesize = itemcount;

		if (response.equals("<"))
			first -= pagesize;
		else if (response.equals(">"))
			first += pagesize;
		else if (response.equals("<<"))
			first -= pagesize * showpages;
		else if (response.equals(">>"))
			first += pagesize * showpages;
		else {
			int page = Integer.parseInt(response);
			first = (page - 1) * pagesize;
		}
		if (first + pagesize > itemcount)
			first = itemcount - pagesize;
		if (first < 0)
			first = 0;
		data.setFirst(first);
	}

	public static List<UIParameter> getParams(final UIComponent component) {
		final ArrayList<UIParameter> list = new ArrayList<UIParameter>();
		for (final UIComponent child : component.getChildren()) {
			if (child instanceof UIParameter) {
				list.add((UIParameter) child);
			}
		}
		return list;
	}
}